﻿using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Devonline.Core;
using Devonline.Http;
using Devonline.Identity.Admin.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace Devonline.Identity.Admin.Controllers
{
    /// <summary>
    /// 资源管理
    /// </summary>    
    [Route("api/[controller]")]
    [SecurityHeaders]
    [ApiController]
    [Authorize]
    public class ResourcesController : ControllerBase
    {
        private readonly IdentityDbContext _context;
        private readonly ILogger<ResourcesController> _logger;
        private readonly ResourceAccessStore _resourceAccessStore;
        private static CancellationToken CancellationToken => CancellationToken.None;

        public ResourcesController(
            IdentityDbContext context,
            ILogger<ResourcesController> logger,
            ResourceAccessStore resourceAccessStore)
        {
            _context = context;
            _logger = logger;
            _resourceAccessStore = resourceAccessStore;
        }

        /// <summary>
        /// 查询资源
        /// </summary>
        /// <returns></returns>
        [HttpGet]
        [EnableQuery]
        public IActionResult Get()
        {
            _logger.LogInformation("user {user} query the resource list", User.Identity.Name);
            return Ok(_context.Resources);
        }
        /// <summary>
        /// 创建资源
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> CreateAsync(ResourceViewModel viewModel)
        {
            _logger.LogInformation("user {user} will add the resource {resource}", User.Identity.Name, viewModel.Name);
            if (await _context.Resources.AnyAsync(x => x.Name == viewModel.Name))
            {
                return BadRequest($"资源 {viewModel.Name} 已经存在!");
            }

            var userId = HttpContext.GetUserId();
            var resource = new Resource
            {
                Name = viewModel.Name,
                Alias = viewModel.Alias,
                Image = viewModel.Image,
                Type = viewModel.Type,
                ParentId = viewModel.ParentId,
                Title = viewModel.Title,
                Content = viewModel.Content,
                ResourceType = viewModel.ResourceType,
                AssignType = viewModel.AssignType,
                OwnerId = viewModel.OwnerId ?? userId,
                Description = viewModel.Description
            };

            // TODO 暂时设置资源的所有者和类型为当前用户
            resource.AssignType = AssignType.User;
            resource.OwnerId = userId;
            resource.Create(User.Identity.Name);
            resource.Update(User.Identity.Name);
            _context.Resources.Add(resource);

            //处理新增附件
            await _context.AddAttachmentsAsync(resource, viewModel.Attachments);
            var result = await _context.SaveChangesAsync();
            if (result >= 1)
            {
                _logger.LogWarning("user {user} success to add the resource {resource}", User.Identity.Name, resource.Name);
                return Ok();
            }

            return BadRequest($"新增资源 {viewModel.Name} 没有成功!");
        }
        /// <summary>
        /// 修改资源
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPut("{id}")]
        public async Task<IActionResult> ChangeAsync(string id, ResourceChangeViewModel viewModel)
        {
            _logger.LogInformation("user {user} will change the resource {resource}", User.Identity.Name, id);
            var resource = await _context.Resources.FindAsync(id);
            if (resource == null)
            {
                return NotFound();
            }

            viewModel.CopyTo(resource);

            //处理附件, 无附件则不用写下面的代码及删除文件的代码
            var files = await _context.UpdateAttachmentsAsync(resource, viewModel.Attachments);
            if (files.IsNotNullOrEmpty() && files.Any(x => x == resource.Image))
            {
                resource.Image = null;
            }

            resource.Update(User.Identity.Name);
            _context.Resources.Update(resource);

            var result = await _context.SaveChangesAsync();
            if (result >= 1)
            {
                _logger.LogWarning("user {user} success to change the resource {resource}", User.Identity.Name, resource.Name);
                files.Delete(_logger);
                return Ok();
            }

            return BadRequest($"修改资源 {viewModel.Name} 没有成功!");
        }
        /// <summary>
        /// 修改资源父级
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost("ChangeParent")]
        public async Task<IActionResult> ChangeParentAsync(ChangeParentViewModel viewModel)
        {
            _logger.LogInformation("user {user} will change the resource {resource} parent to {parent}", User.Identity.Name, viewModel.Id, viewModel.ParentId);
            var resource = await _context.Resources.FindAsync(viewModel.Id);
            if (resource == null)
            {
                return NotFound();
            }

            resource.ParentId = viewModel.ParentId;
            resource.Update(User.Identity.Name);
            _context.Resources.Update(resource);
            var result = await _context.SaveChangesAsync();
            if (result >= 1)
            {
                _logger.LogWarning("user {user} success to change the resource {resource} parent to {parent}", User.Identity.Name, resource.Name, viewModel.ParentId);
                return Ok();
            }

            return BadRequest($"修改资源 {resource.Name} 父级没有成功!");
        }
        /// <summary>
        /// 修改资源所有者
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost("ChangeOwner")]
        public async Task<IActionResult> ChangeOwnerAsync(ChangeOwnerViewModel viewModel)
        {
            _logger.LogInformation("user {user} will change the resource {resource} owner to {owner} and owner type to {ownerType}", User.Identity.Name, viewModel.Id, viewModel.OwnerId, viewModel.AssignType);
            var resource = await _context.Resources.FindAsync(viewModel.Id);
            if (resource == null)
            {
                return NotFound();
            }

            resource.OwnerId = viewModel.OwnerId;
            resource.AssignType = viewModel.AssignType;
            resource.Update(User.Identity.Name);
            _context.Resources.Update(resource);
            var result = await _context.SaveChangesAsync();
            if (result >= 1)
            {
                _logger.LogWarning("user {user} success to change the resource {resource} owner to {owner} and owner type to {ownerType}", User.Identity.Name, resource.Name, viewModel.OwnerId, viewModel.AssignType);
                return Ok();
            }

            return BadRequest($"修改资源 {resource.Name} 所有者没有成功!");
        }
        /// <summary>
        /// 修改资源可访问级别
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost("ChangeLevel")]
        public async Task<IActionResult> ChangeLevelAsync(ResourceChangeLevelViewModel viewModel)
        {
            _logger.LogInformation("user {user} will change the resource {resource} level to {level} and access level to {accessLevel}", User.Identity.Name, viewModel.Id, viewModel.LevelName, viewModel.AccessLevel);
            var resource = await _context.Resources.FindAsync(viewModel.Id);
            if (resource == null)
            {
                return NotFound();
            }

            await _resourceAccessStore.SetLevel(resource, viewModel.LevelName, CancellationToken);
            await _resourceAccessStore.SetAccessLevel(resource, viewModel.AccessLevel, CancellationToken);
            resource.Update(User.Identity.Name);
            _context.Resources.Update(resource);
            var result = await _context.SaveChangesAsync();
            if (result >= 1)
            {
                _logger.LogWarning("user {user} success to change the resource {resource} level to {level} and access level to {accessLevel}", User.Identity.Name, resource.Name, viewModel.LevelName, viewModel.AccessLevel);
                return Ok();
            }

            return BadRequest($"修改资源 {resource.Name} 级别没有成功!");
        }

        /// <summary>
        /// 删除(逻辑删除)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteAsync(string id)
        {
            _logger.LogInformation("user {user} will delete the resource {resource}", User.Identity.Name, id);
            var resource = await _context.Resources.FindAsync(id);
            if (resource == null)
            {
                return NotFound();
            }

            //处理附件, 无附件则不用写下面的代码及删除文件的代码
            var files = await _context.DeleteAttachmentsAsync(id);

            _context.Resources.Remove(resource);
            var result = await _context.SaveChangesAsync();
            if (result >= 1)
            {
                _logger.LogWarning("user {user} success to delete the resource {resource}", User.Identity.Name, resource.Name);
                files.Delete(_logger);
                return Ok();
            }

            return BadRequest($"删除资源 {resource.Name} 出错!");
        }
    }
}
